O projeto foi organizado nos seguintes arquivos:
linkedlist.py: Guarda o funcionamento da lista encadeadaproduto.py: Guarda a classe Product, responsável pelas informações dos produtosestoque.py: Guarda a principal funcionalidade do sistema, a classe Stockmain.py: É o coração do sistema de gerenciamento de estoque, que é mostrado ao usuárioCriamos um guia, contendo as principais missões de cada membro da equipe
1. `adicionar_produto()` (cauã)
2. `remover_produto()` (cauã)
3. `atualizar_produto()` (hertz)
4. `listar_produtos()` (iago)
5. `buscar_produto()` (iago)
6. `buscar_por_categoria(categoria)` (hertz) --> Busca mais complexa e específica.
7. `ordenar_por_quantidade()` (iago) --> Ordena a lista de produtos por quantidade (do menor para o maior).
8. `get_action(string)` (cauã)
9. `main()`(cauã)# Controle de Versão com GitHub
## Configuração Inicial
Clone o repositório localmente:
git clone (link_do_repositório) --> O link ainda será enviado no grupo do whatsapp do projeto pois o repositório ainda não foi criado.
## Fluxo de Trabalho
1. Criar uma branch para cada nova feature:
git checkout -b feature/adicionar-produto
2. Fazer commits frequentes com mensagens descritivas:
git commit -m "Implementa função de adicionar produto"
3. Fazer um push para o GitHub:
git push origin feature/adicionar-produto
4. Abrir um Pull Request para revisão do código
## Documentação de Erros
1. Usar as Issues do GitHub para rastrear erros
2. Ao encontrar um bug:
- Criar uma nova Issue descrevendo o problema
- Adicionar labels relevantes (ex: "bug", "high-priority")
- Atribuir a um membro da equipe, ou você mesmo caso seja o responsável
3. Ao resolver um bug:
- Referenciar o número da Issue no commit:
git commit -m "Corrige erro na atualização de quantidade (#42)"
- Fechar a Issue através do Pull Request ou manualmenteself.element e uma referência self.next para o próximo nó na listaclass LinkedList:
def __init__(self):
self.head: Node = None
self.last: Node = None
#
# Add an element to final index of list.
#
def add(self, element):
node = Node(element)
#
# Check if the list is empty.
#
if self.is_empty():
self.head = node
self.last = node
return
self.last.next = node
self.last = node
def remove(self, element):
if self.is_empty(): # Check if the list is empty.
return None
current = self.head
previous = None # Saving node previous to the node to be removed.
while current is not None:
if current.element == element:
if previous is None:
self.head = current.next
if self.head is None:
self.last = None
else:
previous.next = current.next # Updating the next so that the previous node to be removed is equal to the next of the node that will be removed.
if current.next is None:
self.last = previous
return element
previous = current
current = current.next
return None
#
# Check if the linked list is empty.
#
def is_empty(self) -> bool:
return self.head is None
#
# Return an array with all elements.
#
def get_all(self):
elements = []
if self.is_empty():
return elements
node = self.head
while True:
elements.append(node.element)
node = node.next
if node is None:
break
return elements
#
# Get the first occurrence of element on list.
#
def get(self, element):
if self.is_empty():
return None
node = self.head
while True:
if node.element == element:
return node.element
node = node.next
if node is None:
break
return NoneSeus principais métodos são:
add(self, element): Adiciona um novo nóremove(self, element): Remove um nóis_empty(self): Verifica se a lista encadeada está vaziaget_all(self): Retorna todos os nós da listaget(self, element): Busca um nó existente na listaclass Product:
def __init__(self, id, name, category, quantity, price):
self.id = id
self.name = name
self.category = category
self.quantity = quantity
self.price = price
def __str__(self) -> str:
return f'Product:[id={self.id}, name={self.name}, category={self.category}, quantity={self.quantity}, price={self.price}]'Método mágico __str__: Quando a classe product for chamada em uma função print, ela retornará todas as informações do produto.
É a maior classe, contendo as funções principais do projeto
from linkedlist import LinkedList
from produto import Product
class Stock:
def __init__(self):
self.stock = LinkedList()
self.current_id = 0
self.update_actions = [
{
"action": "1",
"description": "Alterar o nome do produto.",
"function": lambda product, new_value: setattr(product, 'name', new_value)
},
{
"action": "2",
"description": "Alterar a categoria do produto.",
"function": lambda product, new_value: setattr(product, 'category', new_value)
},
{
"action": "3",
"description": "Alterar a quantidade do produto.",
"function": lambda product, new_value: setattr(product, 'quantity', int(new_value))
},
{
"action": "4",
"description": "Alterar o preço do produto.",
"function": lambda product, new_value: setattr(product, 'price', float(new_value))
}
]
# Gerando ID novo a cada criação
def generate_id(self):
self.current_id += 1
return self.current_id
#
# Get product if exists, else return None
#
def get_product(self, id):
## Get all existent products in stock
all_products = self.stock.get_all()
## Find existent product in stock by ID
for product in all_products:
if id == product.id:
return product
return None
def add_product(self, name, category, quantity, price):
id = self.generate_id()
new_product = Product(id, name, category, quantity, price)
self.stock.add(new_product)
print(f"Produto {name} adicionado com sucesso.")
def remove_product(self, id):
product = self.get_product(id)
if product is None:
print("Produto não encontrado.")
return
self.stock.remove(product)
print(f"Produto '{product.name}' removido com sucesso.")
def update_product(self, id):
product = self.get_product(id)
if product is None:
return
for action in self.update_actions:
print(f"{action['action']}: {action['description']}")
action_command = input("Insira o número de qual campo acima você quer alterar: ")
action_object = None
for action in self.update_actions:
if action['action'] == action_command:
action_object = action
if action_object is None:
print(f"Você inseriu uma ação inválida.")
self.update_product(id)
return
new_value = input("Insira o novo valor para o campo informado: ")
action_object['function'](product, new_value)
# Get product if exists by name, else return none
def get_product_by_name(self, name):
all_products = self.stock.get_all()
transformed_name = name.strip().lower()
for product in all_products:
if transformed_name == product.name:
return product
return None
def get_products_by_category(self, category):
products = []
all_products = self.stock.get_all()
transformed_category = category.strip().lower()
for product in all_products:
if transformed_category == product.category:
products.append(product)
return products
#
# Get all products from stock
#
def get_all_products(self):
return self.stock.get_all()
#
# Order by quantity from highest to lowest if stock is not empty
#
def order_by_quantity(self):
if self.stock.is_empty():
return None
## Get all existent produts in stock
all_products = self.stock.get_all()
## Initialize ordered list
ordered_list = []
## Search in all of the products list and return
for i in range(len(all_products)):
highest = None
for product in all_products:
if highest == None or product.quantity >= highest.quantity:
highest = product
ordered_list.append(highest)
all_products.remove(highest)
return ordered_listImplementação correta da lista encadeada através das classes Stock e LinkedList, onde a classe Stock utiliza dos métodos da LinkedList para funcionar, além da classe Product
Trabalho colaborativo usando github através de pull requests
Tratamento de erros e exceções com a função get_product_by_name() e get_product_by_category() na classe Stock
# Get product if exists by name
def get_product_by_name(self, name):
all_products = self.stock.get_all()
transformed_name = name.strip().lower()
for product in all_products:
if transformed_name == product.name:
return product
return None
# Get list of products if exists by category
def get_products_by_category(self, category):
products = []
all_products = self.stock.get_all()
transformed_category = category.strip().lower()
for product in all_products:
if transformed_category == product.category:
products.append(product)
return productsTratamento de erros e exceções com a função get_product_by_name() e get_product_by_category() na classe Stock
Exemplo: o usuário pode inserir o nome “CaChoRRO”. Se tiver apenas um item escrito “cachorro”, ele não vai encontrar, pois precisa digitar exatamente como está, com letras minúsculas e sem espaços.
Porém, ao adicionarmos o .strip() (remove espaços) e o .lower() (deixa todas as letras minúsculas), que são métodos de string, resolvemos esse problema, e o usuário pode encontrar o que deseja.
# Get product if exists by name
def get_product_by_name(self, name):
all_products = self.stock.get_all()
transformed_name = name.strip().lower()
for product in all_products:
if transformed_name == product.name:
return product
return None
# Get list of products if exists by category
def get_products_by_category(self, category):
products = []
all_products = self.stock.get_all()
transformed_category = category.strip().lower()
for product in all_products:
if transformed_category == product.category:
products.append(product)
return productsAlocação dinâmica do ID dos produtos registrados:
Através da função generate_id(), conseguimos gerar dinamicamente o ID dos novos produtos, evitando que seja necessário inserir o ID na hora de cadastrar um novo produto no estoque
class Stock:
# Gerando ID novo a cada criação
def generate_id(self):
self.current_id += 1
return self.current_id
# Adicionar um produto
def add_product(self, name, category, quantity, price):
id = self.generate_id()
new_product = Product(id, name, category, quantity, price)
self.stock.add(new_product)
print(f"Produto {name} adicionado com sucesso.")Escolha de trabalhar com atualização por produtos em dicionários ao invés de listas devido a possibilidade do uso de BIG DATA (grandes quantidades de dados)
Nesse caso, registramos a ação self.update_actions dentro do init
def main():
stock = Stock()
while True:
action = input(
"Digite 1 - para adicionar, remover ou atualizar produtos,\n"
"Digite 2 - para buscar produto, por categoria, por quantidade,\n"
"Digite 3 - para listar os produtos,\n"
"Digite Q - para sair."
).upper()
print("-" * 60)
if action == "1":
while True:
subaction = input(
"Digite 1 - para adicionar um produto,\n"
"Digite 2 - para remover um produto,\n"
"Digite 3 - para atualizar um produto,\n"
"Digite Q - para sair."
).upper()
print("-" * 60)
if subaction == "1":
name = input("Digite o nome do produto: ")
category = input("Digite a categoria do produto: ")
quantity = int(input("Digite a quantidade do produto: "))
price = float(input("Digite o preço do produto: "))
stock.add_product(name, category, quantity, price)
print("-" * 60)
elif subaction == "2":
id = int(input("Digite o ID do produto a ser removido: "))
stock.remove_product(id)
print("-" * 60)
elif subaction == "3":
product_id = int(input("Digite o id do produto a ser atualizado: "))
stock.update_product(product_id)
elif subaction == "Q":
break
else:
print("Ação inválida.")class Stock:
def __init__(self):
self.stock = LinkedList()
self.current_id = 0
self.update_actions = [
{
"action": "1",
"description": "Alterar o nome do produto.",
"function": lambda product, new_value: setattr(product, 'name', new_value)
},
{
"action": "2",
"description": "Alterar a categoria do produto.",
"function": lambda product, new_value: setattr(product, 'category', new_value)
},
{
"action": "3",
"description": "Alterar a quantidade do produto.",
"function": lambda product, new_value: setattr(product, 'quantity', int(new_value))
},
{
"action": "4",
"description": "Alterar o preço do produto.",
"function": lambda product, new_value: setattr(product, 'price', float(new_value))
}
]get_product() da classe StockObrigado pela atenção!